package com.tangding.net.tcp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.google.common.base.Strings;
import com.tangding.common.logx.LogHelp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

@Service
@Scope("prototype")
public class GameNettyServer {
	
	@Autowired
	private GameServerChannelInitializer channelInitializer;
	
	static EventLoopGroup bossGroup;
	static EventLoopGroup workerGroup;
	private String serverName = "Server";
	private void initBossGroup() {
		if (bossGroup == null || bossGroup.isShutdown() || bossGroup.isShuttingDown() || bossGroup.isTerminated()) {
			bossGroup = new NioEventLoopGroup(0, new GameThreadFactory(serverName + " boss", true));
		}
	}
	
	private void initWorkerGroup() {
		if (workerGroup == null || workerGroup.isShutdown() || workerGroup.isShuttingDown() || workerGroup.isTerminated()) {
			workerGroup = new NioEventLoopGroup(0, new GameThreadFactory(serverName + " worker", true));
		}
	}
	
	public void start(String host, int port, String serverName) {
		if (!Strings.isNullOrEmpty(serverName)) {
			this.serverName = serverName;
		}
		start(host, port);
	}
	
	public void start(String host, int port) {
		initBossGroup();
		initWorkerGroup();
		
		ServerBootstrap b = new ServerBootstrap();
		b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
		.childHandler(channelInitializer).option(ChannelOption.SO_BACKLOG, 128);
		b.childOption(ChannelOption.SO_KEEPALIVE, true)
		.childOption(ChannelOption.TCP_NODELAY, false)
		.childOption(ChannelOption.SO_REUSEADDR, true)
		.childOption(ChannelOption.SO_RCVBUF, 32 * 1024)
		.childOption(ChannelOption.SO_SNDBUF, 32 * 1024)
		.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, WriteBufferWaterMark.DEFAULT)
		;
		b.bind(host, port);
		LogHelp.doLogApp("tcp server bind[" + host + ":" + port + "] succ!!");
	}
	
	static {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                try {
                	workerGroup.shutdownGracefully();
                    bossGroup.shutdownGracefully();
                    LogHelp.doLogApp("netty shutdown gracefully...");
                } catch (Throwable t) {
                    LogHelp.doLogException(t);
                }
            }
        }, "MoonShutdownHook"));
    }

	public String getServerName() {
		return serverName;
	}

	public void setServerName(String serverName) {
		this.serverName = serverName;
	}
}